/***********************************************************************************
 * 文件名： hc32_base_uart.c
 * 作者： 刘言
 * 版本： 1
 * 说明：
 * 		仅 HC32F005 系列拥有 base uart，它们是 UART0 UART1 ，其它型号MCU请使用 
 *  hc32_general_uart.c 。
 *      中断入口统一定义在 isr.c 中。
 * 修改记录：
 * 	2020/8/18: 初版。 刘言。
***********************************************************************************/
#include "HC32_LyLib.h"
#include "components\soft_fifo\soft_fifo.h"
#include "hc32_base_uart.h"		

#if (HC32_MCU_SERIES == HC32F005)

// UART0 --------------------------------

void Tim0_Init();

#if (UART0_EN_TXBUFF == 1)      // 开启发送缓存

static u8 mUart0TxBuff[UART0_TXBUFF_SIZE];
static SoftFifo mUart0Fifo;     // 实例化1个 SoftFifo，注意不支持多线程（包括中断）同时操作！
static volatile bool mUart0Sending = false;      // 正在发送

void Uart0_SendComplete()       // 运行在中断线程
{
    //if (!SoftFifo_IsEmpty(&mUart0Fifo))   // 缓存不为空，说明有数据需要发送 
    if(mUart0Fifo.FreeCount != UART0_TXBUFF_SIZE)     // 高效率等效判断 缓存不为空
    {
        M0P_UART0->SBUF = SoftFifo_Read(&mUart0Fifo);   // 继续发送
    }
    else    // 缓存为空， 说明发送任务完毕了
    {
        mUart0Sending = false;
#ifdef _UART0_USE_HALF_DUPLEX
        _UART0_PIN_RX_MODE;
#endif
    }
}

#endif

void Uart0_Init()
{
    // 端口设置,建议在别处初始化端口

    // 时钟门控
    // SYSCTRL_ENABLE_UART0_CLK; 已统一开启

#if (UART0_EN_TXBUFF == 1)      // 开启发送缓存
    SoftFifo_Init(&mUart0Fifo,mUart0TxBuff,UART0_TXBUFF_SIZE); // 初始化FIFO
#endif

    // 初始化 TIM0 产生波特率
    Tim0_Init(); 

    // UART0 具体设置
    M0P_UART0->SCON =   (1 << 9)   // 双倍波特率
                      | (1 << 6) // 模式1 ： 1起始位，8数据位，1停止位； 模式3： 1起始位，8数据位，2停止位
                      | (1 << 4) // 使能收发
                      | (UART0_EN_TXBUFF << 1)  // 使能发送中断（启用发送缓冲必须使能中断）
                      | (UART0_RIEN << 0) // 使能接收中断
        ;
    M0P_UART0->ICR = 0; // 清除标志位

#if (UART0_RIEN == 1 || UART0_EN_TXBUFF == 1)
    NVIC_ClearPendingIRQ(UART0_IRQn); // 清除NVIC中断标志位
    NVIC_SetPriority(UART0_IRQn, 3);  // 优先级 3 （0~3）
    NVIC_EnableIRQ(UART0_IRQn);       // NVIC允许中断
#endif
}

#if (UART0_EN_TXBUFF == 1)      // 开启发送缓存
// 缓存模式发送1个字节
void Uart0_SendByte(u8 c)
{
    bool ret = false;
    while(ret == false) // 死等直到写入缓存成功
    {
        M0P_UART0->SCON_f.TIEN = 0;     // 禁止发送完成中断，确保不会在中断中同时操作SoftFifo
        ret = SoftFifo_Write(&mUart0Fifo, c);
        M0P_UART0->SCON_f.TIEN = 1;     // 允许发送完成中断
    }
    if(mUart0Sending == false)      // 不在发送中
    {
        mUart0Sending = true;
#ifdef _UART0_USE_HALF_DUPLEX
        _UART0_PIN_TX_MODE;
#endif
        M0P_UART0->SBUF = SoftFifo_Read(&mUart0Fifo);   // 启动发送
    }
}
#else
// 查询模式发送1个字节
void Uart0_SendByte(u8 c)
{
#ifdef _UART0_USE_HALF_DUPLEX
    _UART0_PIN_TX_MODE;
#endif
    M0P_UART0->SBUF = c;
    while(M0P_UART0->ISR_f.TI == 0);
    M0P_UART0->ICR_f.TICLR = 0;
#ifdef _UART0_USE_HALF_DUPLEX
    _UART0_PIN_RX_MODE;
#endif
}
#endif

// 发送一串数据
void Uart0_Send(const u8 *buff, u16 Length)
{
    while(Length--)
	{
		Uart0_SendByte(*buff);
		buff++;
	}
}

// 设置波特率
void Uart0_SetBaud(u32 baud)
{
    M0P_TIM0->ARR = 0x10000-((UART_PCLK*2)/(baud*32));       // 重载值
}


// UART1 --------------------------------

void Tim1_Init();

#if (UART1_EN_TXBUFF == 1)      // 开启发送缓存

static u8 mUart1TxBuff[UART1_TXBUFF_SIZE];
static SoftFifo mUart1Fifo;
static volatile bool mUart1Sending = false;      // 正在发送

void Uart1_SendComplete()
{
    //if (!SoftFifo_IsEmpty(&mUart1Fifo))   // 缓存不为空，说明有数据需要发送 
    if(mUart1Fifo.FreeCount != UART1_TXBUFF_SIZE)     // 高效率等效判断 缓存不为空
    {
        M0P_UART1->SBUF = SoftFifo_Read(&mUart1Fifo);   // 继续发送
    }
    else    // 缓存为空， 说明发送任务完毕了
    {
        mUart1Sending = false;
#ifdef _UART1_USE_HALF_DUPLEX
        _UART1_PIN_RX_MODE;
#endif
    }
}

#endif

void Uart1_Init()
{
    // 端口设置,建议在别处初始化端口

    // 时钟门控
    // SYSCTRL_ENABLE_UART1_CLK; 已统一开启

#if (UART1_EN_TXBUFF == 1)      // 开启发送缓存
    SoftFifo_Init(&mUart1Fifo,mUart1TxBuff,UART1_TXBUFF_SIZE); // 初始化FIFO
#endif

    // 初始化 TIM1 产生波特率
    Tim1_Init(); 

    // UART1 具体设置
    M0P_UART1->SCON =   (1 << 9)   // 双倍波特率
                      | (1 << 6) // 模式1 ： 1起始位，8数据位，1停止位； 模式3： 1起始位，8数据位，2停止位
                      | (1 << 4) // 使能收发
                      | (UART1_EN_TXBUFF << 1)  // 使能发送中断（启用发送缓冲必须使能中断）
                      | (UART1_RIEN << 0) // 使能接收中断
        ;
    M0P_UART1->ICR = 0; // 清除标志位

#if (UART1_RIEN == 1 || UART1_EN_TXBUFF == 1)
    NVIC_ClearPendingIRQ(UART1_IRQn); // 清除NVIC中断标志位
    NVIC_SetPriority(UART1_IRQn, 3);  // 优先级 3 （0~3）
    NVIC_EnableIRQ(UART1_IRQn);       // NVIC允许中断
#endif
}

#if (UART1_EN_TXBUFF == 1)      // 开启发送缓存
// 缓存模式发送1个字节
void Uart1_SendByte(u8 c)
{
    bool ret = false;
    while(ret == false) // 死等直到写入缓存成功
    {
        M0P_UART1->SCON_f.TIEN = 0;     // 禁止发送完成中断，确保不会在中断中同时操作SoftFifo
        ret = SoftFifo_Write(&mUart1Fifo, c);
        M0P_UART1->SCON_f.TIEN = 1;     // 允许发送完成中断
    }
    if(mUart1Sending == false)      // 不在发送中
    {
        mUart1Sending = true;
#ifdef _UART1_USE_HALF_DUPLEX
        _UART1_PIN_TX_MODE;
#endif
        M0P_UART1->SBUF = SoftFifo_Read(&mUart1Fifo);   // 启动发送
    }
}
#else
// 查询模式发送1个字节
void Uart1_SendByte(u8 c)
{
#ifdef _UART1_USE_HALF_DUPLEX
    _UART1_PIN_TX_MODE;
#endif
    M0P_UART1->SBUF = c;
    while(M0P_UART1->ISR_f.TI == 0);
    M0P_UART1->ICR_f.TICLR = 0;
#ifdef _UART1_USE_HALF_DUPLEX
    _UART1_PIN_RX_MODE;
#endif
}
#endif

// 发送一串数据
void Uart1_Send(const u8 *buff, u16 Length)
{
    while(Length--)
	{
		Uart1_SendByte(*buff);
		buff++;
	}
}

// 设置波特率
void Uart1_SetBaud(u32 baud)
{
    M0P_TIM1->ARR = 0x10000-((UART_PCLK*2)/(baud*32));       // 重载值
}


#endif

